#include "head.h"
// 1.0
// 用于服务端向客户端发送文件

//int transFile(int netfd)
//{
//    char filename[] = "file1";
//    send(netfd,filename,5,0);//发送文件名字
//    int fd = open(filename,O_RDWR);//打开该文件
//    ERROR_CHECK(fd,-1,"open");
//    char buf[1000]={0};
//    int sret = read(fd,buf,sizeof(buf));//读取文件内容(磁盘文件)
//    send(netfd,buf,sret,0);//发送给客户端
//    return 0;
//}

// 2.0 小文件发送
//typedef struct train_s{
//    //小火车协议
//    int length;// 火车头，装在内容的长度
//    char data[1000];// 火车车厢，要发送的内
//    // char 数组 不是表示字符串 可以保存任何数据（二进制等）
//    // 1000 不是火车车厢实际大小，是上限
//}train_t;
//
//int transFile(int netfd)
//{
//    train_t train;
//    char filename[] = "file1";
//    train.length = sizeof(filename);
//    //内容靠复制
//    memcpy(train.data,filename,train.length);
//    send(netfd,&train.length,sizeof(train.length),0);//发送火车头
//    send(netfd,train.data,train.length,0);//发送火车车厢
//    
//    // “小火车协议”发送数据
//    int fd = open(filename,O_RDWR);//打开file1文件
//    ssize_t sret = read(fd,train.data,sizeof(train.data));
//    train.length = sret;
//    send(netfd,&train.length,sizeof(train.length),0);//发送火车头
//    send(netfd,train.data,train.length,0);//发送火车车厢
//    close(fd);
//    return 0;
//}

// 3.0 大文件发送
//typedef struct train_s{
//    int length;
//    char data[1000];
//}train_t;
//int transFile(int netfd)
//{
//    char filename[] = "file1";
//    train_t train;
//    train.length = sizeof(filename);
//    memcpy(train.data,filename,train.length);
//    // MSG_NOSIGNAL：不会产生SIGPIPE信号，
//    // 因为当客户端读关闭提前关闭，服务器段的写端会自动触发SIGPIPE把子进程终止，
//    // 同时父子进程之间一直存在socketpipe，子进程工作结束，但是对于父进程仍然可以从socketpipe管道中可以读取数据，子进程写端关闭读段必然一直陷入死循环
//    send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
//    send(netfd,train.data,train.length,MSG_NOSIGNAL);
//
//    int fd = open(filename,O_RDWR);
//    while(1)
//    {
//        ssize_t sret = read(fd,train.data,sizeof(train.data));//火车车厢
//        train.length = sret;//火车车头
//        send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);//发送火车车头
//        send(netfd,train.data,train.length,MSG_NOSIGNAL);//发送火车车厢
//        // 如果数据读完了，此时火车头与火车车厢都为空，即表示数据发送结束！
//        if(sret == 0)
//        {
//            break;
//        }
//    }
//    close(fd);
//    return 0;
//}

// v4.0 进度条显示
//typedef struct train_s{
//    int length;
//    char data[1000];
//}train_t;
//int transFile(int netfd)
//{
//    char filename[] = "file1";
//    train_t train;
//    train.length = sizeof(filename);
//    memcpy(train.data,filename,train.length);
//    // MSG_NOSIGNAL：不会产生SIGPIPE信号，
//    // 因为当客户端读关闭提前关闭，服务器段的写端会自动触发SIGPIPE把子进程终止，
//    // 同时父子进程之间一直存在socketpipe，子进程工作结束，但是对于父进程仍然可以从socketpipe管道中可以读取数据，子进程写端关闭读段必然一直陷入死循环
//    send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
//    send(netfd,train.data,train.length,MSG_NOSIGNAL);
//
//    // 发送文件长度
//    struct stat statbuf;
//    int fd = open(filename,O_RDWR);
//    fstat(fd,&statbuf);// 获取文件状态信息
//    train.length = sizeof(off_t);// 获取文件大小
//    memcpy(train.data,&statbuf.st_size,train.length);
//    send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
//    send(netfd,train.data,train.length,MSG_NOSIGNAL);
//
//    while(1)
//    {
//        ssize_t sret = read(fd,train.data,sizeof(train.data));//火车车厢
//        train.length = sret;//火车车头
//        send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);//发送火车车头
//        send(netfd,train.data,train.length,MSG_NOSIGNAL);//发送火车车厢
//        // 如果数据读完了，此时火车头与火车车厢都为空，即表示数据发送结束！
//        if(sret == 0)
//        {
//            break;
//        }
//    }
//    close(fd);
//    return 0;
//}

// v4.1 使用mmap内存映射机制
typedef struct train_s{
    int length;
    char data[1000];
}train_t;
int transFile(int netfd)
{
    char filename[] = "file1";
    train_t train;
    train.length = sizeof(filename);
    memcpy(train.data,filename,train.length);
    // MSG_NOSIGNAL：不会产生SIGPIPE信号，
    // 因为当客户端读关闭提前关闭，服务器段的写端会自动触发SIGPIPE把子进程终止，
    // 同时父子进程之间一直存在socketpipe，子进程工作结束，但是对于父进程仍然可以从socketpipe管道中可以读取数据，子进程写端关闭读段必然一直陷入死循环
    send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netfd,train.data,train.length,MSG_NOSIGNAL);

    // 发送文件长度
    struct stat statbuf;
    int fd = open(filename,O_RDWR);
    fstat(fd,&statbuf);// 获取文件状态信息
    train.length = sizeof(off_t);// 获取文件大小
    memcpy(train.data,&statbuf.st_size,train.length);
    send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netfd,train.data,train.length,MSG_NOSIGNAL);

    char *p = (char *)mmap(NULL,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    ERROR_CHECK(p,MAP_FAILED,"mmap");
    off_t cursize = 0;
    while(1)
    {
        if(cursize >= statbuf.st_size)
        {
            break;
        }
        // 发送文件长度大于1000，我们只发送1000
        if(statbuf.st_size - cursize >= 1000)
        {
            train.length = 1000;
        }else{
            //若是火车长度不足1000，则发剩余内容
            train.length = statbuf.st_size - cursize;
        }
        send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        // 每一节车厢的数据从映射区发送过去的
        send(netfd,p+cursize,train.length,MSG_NOSIGNAL);
        cursize += train.length;
    }
    // 数据发送完后，要发送一个0字节的头文件给客户端
    train.length = 0;
    send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netfd,train.data,train.length,MSG_NOSIGNAL);
    munmap(p,statbuf.st_size);
    close(fd);
    return 0;
}

